package jmine.tec.rpc.common.serialization.json;

import jmine.tec.json.JSON;
import jmine.tec.rpc.RPCMessages;
import jmine.tec.rpc.common.RPCException;
import jmine.tec.rpc.common.provider.RestServiceProvider;

import org.springframework.beans.factory.InitializingBean;

/**
 * Conversor de beans para objetos JSON.
 * 
 * @author lundberg
 */
public class JSONConverter implements InitializingBean {

    private RestServiceProvider provider;

    private final JSONConverterStrategy[] strategies;

    /**
     * Construtor
     * 
     * @param strategies strategies
     */
    public JSONConverter(JSONConverterStrategy[] strategies) {
        this.strategies = strategies;
    }

    /**
     * Converte o objeto em JSON
     * 
     * @param object object
     * @return json
     */
    public JSON toJSON(Object object) {
        return this.toJSON(this.createContext(), object);
    }

    /**
     * Converte o objeto em JSON, dentro de um contexto de conversão
     * 
     * @param context context
     * @param object object
     * @return json
     */
    JSON toJSON(JSONConversionContext context, Object object) {
        for (JSONConverterStrategy strategy : this.strategies) {
            if (strategy.matchesJava(object)) {
                return strategy.toJSON(context, object);
            }
        }
        throw new RPCException(RPCMessages.NO_SERIALIZATION_STRATEGY_FOUND.create(object));
    }

    /**
     * Converte o JSON em objeto java
     * 
     * @param json json
     * @return object
     */
    public Object toJava(JSON json) {
        return this.toJava(this.createContext(), json);
    }

    /**
     * Converte o JSON em objeto java, dentro de um contexto de conversão
     * 
     * @param context context
     * @param json json
     * @return object
     */
    Object toJava(JSONConversionContext context, JSON json) {
        for (JSONConverterStrategy strategy : this.strategies) {
            if (strategy.matchesJSON(json)) {
                return strategy.toJava(context, json);
            }
        }
        throw new RPCException(RPCMessages.NO_DESERIALIZATION_STRATEGY_FOUND.create(json));
    }

    /**
     * Cria um contexto de conversão JSON
     * 
     * @return context
     */
    private JSONConversionContext createContext() {
        return new JSONConversionContext(this);
    }

    /**
     * {@inheritDoc}
     */
    public void afterPropertiesSet() throws Exception {
        for (JSONConverterStrategy strategy : this.strategies) {
            if (strategy instanceof RestServiceProviderAware) {
                ((RestServiceProviderAware) strategy).setProvider(this.provider);
            }
        }
    }

    /**
     * @param provider the provider to set
     */
    public void setProvider(RestServiceProvider provider) {
        this.provider = provider;
    }
}
